#include <iostream>
#include <string.h>
#include "src/debug/DebugAssertion.h"
#include "src/crypto/MACProvider.h"

using namespace std;
using namespace nacos;

typedef struct _HMACSHA1TestCase {
    const char *key;
    size_t key_len;
    const char *data;
    size_t data_len;
    const char *digest;
} HMACSHA1TestCase;

HMACSHA1TestCase HMACSHA1TestCases[] = {
    {"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20, "Hi There", 8, "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00"},
    {"Jefe", 4, "what do ya want for nothing?", 28, "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79"},
    {"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20, "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", 50, "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3"},
    {"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25, "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", 50, "\x4c\x90\x07\xf4\x02\x62\x50\xc6\xbc\x84\x14\xf9\xbf\x50\xc8\x6c\x2d\x72\x35\xda"},
    {"\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20, "Test With Truncation", 20, "\x4c\x1a\x03\x42\x4b\x55\xe0\x7f\xe7\xf2\x7b\xe1\xd5\x8b\xb9\x32\x4a\x9a\x5a\x04"},
    {"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 80, "Test Using Larger Than Block-Size Key - Hash Key First", 54, "\xaa\x4a\xe5\xe1\x52\x72\xd0\x0e\x95\x70\x56\x37\xce\x8a\x3b\x55\xed\x40\x21\x12"},
    {"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 80, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73, "\xe8\xe9\x9d\x0f\x45\x23\x7d\x78\x6d\x6b\xba\xa7\x96\x5c\x78\x08\xbb\xff\x1a\x91"},
};

bool testHMACSHA1() {
    //Actually, I've no idea why Alibaba is still using this old-school MAC algorithm :(
    cout << "In function testHMACSHA1()" << endl;
    cout << "Getting MAC algorithm" << endl;
    cout << "Test case acquired at https://datatracker.ietf.org/doc/html/rfc2202" << endl;

    IMAC *digester = MACProvider::getMAC(MACProvider::HMAC_SHA1);
    SHOULD_BE_TRUE(digester != NULL, "Should be able to get a IMAC* from MACProvider");

    for (size_t i = 0; i < sizeof(HMACSHA1TestCases) / sizeof(HMACSHA1TestCase); i++) {
        const void *k = (const void*)HMACSHA1TestCases[i].key;
        size_t kl = HMACSHA1TestCases[i].key_len;

        const void *data = (const void*)HMACSHA1TestCases[i].data;
        size_t dl = HMACSHA1TestCases[i].data_len;

        char out[256] = {0};
        size_t out_l = sizeof(out);

        digester->getMac(k, kl, data, dl, out, &out_l);
        SHOULD_BE_TRUE(out_l == 20, "Digested data should be 20-bytes long");

        SHOULD_BE_TRUE(memcmp(out, HMACSHA1TestCases[i].digest, 20)  == 0, "Checking digested data with test vector");

        cout << "Test case " << i + 1 << ": out_l=" << out_l << " passed." <<endl;
    }

    return true;
}